<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Go 语法基础">
<meta name="twitter:description" content="<p>iota定义常量；值类型和引用类型；流程控制语句；结构体：构造函数，Go中的面向对象；函数、方法和接口：值类型接收者和指针类型接收者</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/gotour-basic-grammar.html"/>
<meta property="og:title" content="来玩魔王的咚 | Go 语法基础" />
<meta property="og:description" content="<p>iota定义常量；值类型和引用类型；流程控制语句；结构体：构造函数，Go中的面向对象；函数、方法和接口：值类型接收者和指针类型接收者</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>iota定义常量；值类型和引用类型；流程控制语句；结构体：构造函数，Go中的面向对象；函数、方法和接口：值类型接收者和指针类型接收者</p>" />

    <meta name="tags" content="gotour" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li class="active"><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-11-20 10:00:00+08:00">
                <script>document.write(moment('2020-11-20 10:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-11-20 10:00:00+08:00">
                <script>document.write(moment('2020-11-20 12:40:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Go 语法基础
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#you-ya-de-ding-yi-chang-liang-iota">优雅的定义常量 iota</a></li>
<li><a href="#zhi-lei-xing-he-yin-yong-lei-xing">值类型和引用类型</a></li>
<li><a href="#liu-cheng-kong-zhi">流程控制</a><ul>
<li><a href="#if-else-fen-zhi-pan-duan">if / else 分支判断</a></li>
<li><a href="#switch-case-yu-ju">switch case 语句</a></li>
<li><a href="#for-yu-ju">for 语句</a></li>
<li><a href="#label">label</a></li>
<li><a href="#goto">goto</a></li>
</ul>
</li>
<li><a href="#jie-gou-ti">结构体</a><ul>
<li><a href="#ding-yi-jie-gou-ti">定义结构体</a></li>
<li><a href="#gong-chang-mo-shi-gou-zao-han-shu">工厂模式（构造函数）</a></li>
<li><a href="#mian-xiang-dui-xiang">面向对象</a></li>
</ul>
</li>
<li><a href="#han-shu-fang-fa-he-jie-kou">函数、方法和接口</a><ul>
<li><a href="#zhi-lei-xing-jie-shou-zhe-he-zhi-zhen-lei-xing-jie-shou-zhe">值类型接收者和指针类型接收者</a></li>
<li><a href="#xiao-jie">小结</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="you-ya-de-ding-yi-chang-liang-iota"><a class="toclink" href="#you-ya-de-ding-yi-chang-liang-iota">优雅的定义常量 iota</a></h3>
<p>iota是go语言的常量计数器,只能在常量的表达式中使用（也就是必须在const里面使用）。<br>
简单讲就是，iota在const关键字出现时被重置为0(const内部的第一行之前)，const中每新增一行常量声明将使iota计数自增1（从0开始）。所以第一个值就是0，之后的值依次就是1、2。配合表达式还有下划线等等，也可以有很多高级的写法，效果就是让代码定义常量变的更加优雅。以后在定义一组有规律的常量的时候，可以再深入一下，看看如何用iota优雅的实现。  </p>
<h3 id="zhi-lei-xing-he-yin-yong-lei-xing"><a class="toclink" href="#zhi-lei-xing-he-yin-yong-lei-xing">值类型和引用类型</a></h3>
<p>值类型：变量直接存储值，内存通常在栈中分配。<br>
基本数据类型int、float、bool、string，以及数组和struct，这些都是值类型。<br>
引用类型：变量存储的是一个地址，这个地址存储最终的值。内存通常在堆上分配，通过GC回收。<br>
指针、slice、map、chan等都是引用类型。<br>
上面提到了栈（栈是后进先出的）和堆。如果是值类型，那么数值就直接存在栈里。如果是引用类型，这个变量也是在栈里的，但是栈里的值存的是堆里对应的地址，通过栈里的地址可以查找到堆里对应的地址空间里的值。  </p>
<p><img alt="值类型和引用类型" src="/images/go/27_data-type.jpg"></p>
<h3 id="liu-cheng-kong-zhi"><a class="toclink" href="#liu-cheng-kong-zhi">流程控制</a></h3>
<h4 id="if-else-fen-zhi-pan-duan"><a class="toclink" href="#if-else-fen-zhi-pan-duan">if / else 分支判断</a></h4>
<p>语法：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// 第一种</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">condition1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 第二种</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">condition1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 第三种</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">condition</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">condition2</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">condition3</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="switch-case-yu-ju"><a class="toclink" href="#switch-case-yu-ju">switch case 语句</a></h4>
<p>语法：</p>
<div class="highlight"><pre><span></span><code><span class="k">switch</span><span class="w"> </span><span class="nx">var1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">val1</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">val2</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">val3</span><span class="p">.</span><span class="w"> </span><span class="nx">val4</span><span class="w"> </span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">default</span><span class="p">:</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>go语言了，case结尾不需要加break，并且语句也不会继续匹配后面的条件。如果需要继续匹配之后的条件，可以添加fallthrough关键字。  </p>
<p>switch后面的表达式不是必需的。在此种情况下，整个switch结构与多个 if / else 的逻辑作用等同：</p>
<div class="highlight"><pre><span></span><code><span class="k">switch</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">100</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;分数超出范围&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">100</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是：A+满分&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">90</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是: A&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">80</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是：B&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">70</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是：C&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">60</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是：D&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">case</span><span class="w"> </span><span class="nx">score</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;你的成绩是：E&quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">default</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;0分或者输入无效&quot;</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>可以用一个简单的语句做初始化，需要用分号分隔：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// 这种是先给i初始化，后面的case判断i的值</span><span class="w"></span>
<span class="k">switch</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="mi">1</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">default</span><span class="p">:</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 这种是给j初始化，后面的分号不能省</span><span class="w"></span>
<span class="k">switch</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">default</span><span class="p">:</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="for-yu-ju"><a class="toclink" href="#for-yu-ju">for 语句</a></h4>
<p>写法一：</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="nx">初始化语句</span><span class="p">;</span><span class="w"> </span><span class="nx">条件判断</span><span class="p">;</span><span class="w"> </span><span class="nx">变量修改</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>写法二：</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="nx">条件</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 如果条件时true，就是个死循环</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 上面可以简写，省掉true</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>在go语言里没有while，这里就已经是while的效果了。  </p>
<p>写法三
for range 用来遍历数组、slice、map、chan。<br>
用下面的例子举例了，遍历后获得2个值，i是下标，v是值：</p>
<div class="highlight"><pre><span></span><code><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;abcdefg&quot;</span><span class="w">  </span><span class="c1">// 字符串也能遍历</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">v</span><span class="p">))</span><span class="w"> </span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p><strong>break</strong>：跳出当前循环。<br>
<strong>continue</strong>：结束本次循环，进入下一次继续。  </p>
<h4 id="label"><a class="toclink" href="#label">label</a></h4>
<p>for、switch 或 select 语句都可以配合标签（label）形式的标识符使用，即某一行第一个以冒号（:）结尾的单词（gofmt 会将后续代码自动移至下一行）。标签的名称是大小写敏感的，为了提升可读性，一般建议使用全部大写字母。<br>
在多级嵌套语句中，非常有用。下面例子的continue后面指定了标签，这样就直接作为外层的for循环的continue操作：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="nx">LABEL1</span><span class="p">:</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="nx">j</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">                </span><span class="k">continue</span><span class="w"> </span><span class="nx">LABEL1</span><span class="w"></span>
<span class="w">            </span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;i is: %d, and j is: %d\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>break 标签的效果和 continue 是一样的，差别只是break和continue的动作。  </p>
<h4 id="goto"><a class="toclink" href="#goto">goto</a></h4>
<p>原始的goto语句也有，要配合label标签，不建议使用：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">i</span><span class="o">:=</span><span class="mi">0</span><span class="w"></span>
<span class="w">    </span><span class="nx">HERE</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="nb">print</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">i</span><span class="o">++</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">i</span><span class="o">==</span><span class="mi">5</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">goto</span><span class="w"> </span><span class="nx">HERE</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>上面的这种是逆向的使用goto，使用标签和goto语句是不被鼓励的。而且总有更加可读的替代方案来实现相同的需求。<br>
如果必须使用goto，应当只使用正序的标签（标签位于goto语句之后），但注意标签和goto语句之间不能出现定义新变量的语句，否则会导致编译失败。  </p>
<h3 id="jie-gou-ti"><a class="toclink" href="#jie-gou-ti">结构体</a></h3>
<p>在Go语言中的结构体（就相当于其它语言里的class）：</p>
<ul>
<li>用来定义复杂的数据结构</li>
<li>可以包含多个字段（属性）</li>
<li>结构体类型可以定义方法，注意和函数的区分</li>
<li>结构体是值类型，创建空结构体用new函数</li>
<li>结构体可以嵌套</li>
<li>Go语言没有class类型，只有struct类型</li>
</ul>
<h4 id="ding-yi-jie-gou-ti"><a class="toclink" href="#ding-yi-jie-gou-ti">定义结构体</a></h4>
<p>struct 声明：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="p">(</span><span class="nx">标识符</span><span class="p">)</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">field1</span><span class="w"> </span><span class="kd">type</span><span class="w"></span>
<span class="w">    </span><span class="nx">field2</span><span class="w"> </span><span class="kd">type</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="gong-chang-mo-shi-gou-zao-han-shu"><a class="toclink" href="#gong-chang-mo-shi-gou-zao-han-shu">工厂模式（构造函数）</a></h4>
<p>在go语言中的struct不像其他语言里的class有构造函数。struct没有构造函数，一般可以使用工厂模式来解决这个问题：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">model</span><span class="w"></span>

<span class="c1">// 名称是小写，就是不让你访问的</span><span class="w"></span>
<span class="kd">type</span><span class="w"> </span><span class="nx">student</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Age</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 外部要调用的是这个工厂函数，返回上面的经过构造函数处理的完成了初始化的结构体，即实例</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">NewStudent</span><span class="p">(</span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">age</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="nx">student</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 这里可以补充其他构造函数里的代码</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">student</span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">Name</span><span class="p">:</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="nx">Age</span><span class="p">:</span><span class="w"> </span><span class="nx">age</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>然后可以在别处调用：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="s">&quot;model&quot;</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">model</span><span class="p">.</span><span class="nx">NewStudent</span><span class="p">(</span><span class="s">&quot;Adam&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="o">*</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="mian-xiang-dui-xiang"><a class="toclink" href="#mian-xiang-dui-xiang">面向对象</a></h4>
<p>在go语言中并没有明确的面向对象的说法，可以将struct类比作其它语言中的class。<br>
在go语言中，没有继承，只有组合。下面说的继承就当是和别的语言的类比。  </p>
<p><strong>constructor 构造函数</strong><br>
通过结构体的工厂模式返回实例来实现  </p>
<p><strong>Encapsulation 封装</strong><br>
通过自动的大小写控制可见  </p>
<p><strong>Inheritance 继承</strong><br>
结构体嵌套匿名结构体  </p>
<p><strong>Composition 组合</strong><br>
结构体嵌套有名结构体  </p>
<p><strong>Polymorphism 多态</strong><br>
通过接口实现  </p>
<p><strong>继承与组合的区别</strong><br>
这里说的继承和组合是面向对象的概念，不过go语言应该可以参考：</p>
<ul>
<li>继承：建立了派生类与基类之间的关系，它是一种“是”的关系，比如：狗是动物。当类之间有很多相同的功能，提取这些共同的功能做成基类，用继承比较好。</li>
<li>组合：建立了类与组合类之间的关系，它是一种“有”的关系，比如老师有生日，老师有课程，老师有学生</li>
</ul>
<h3 id="han-shu-fang-fa-he-jie-kou"><a class="toclink" href="#han-shu-fang-fa-he-jie-kou">函数、方法和接口</a></h3>
<p>Go 函数：<a href="https://steeed.gitee.io/gopl-functions.html">https://steeed.gitee.io/gopl-functions.html</a> 。  </p>
<ul>
<li>延迟函数调用（defer）</li>
<li>Panic异常</li>
<li>Recover捕获异常</li>
</ul>
<p>Go 方法和接口：<a href="https://steeed.gitee.io/gopl-methods-interfaces.html">https://steeed.gitee.io/gopl-methods-interfaces.html</a> 。  </p>
<ul>
<li>指针接收者的方法</li>
<li>方法变量与方法表达式</li>
<li>方法变量</li>
<li>方法表达式：T.f 或 (*T).f</li>
<li>接口值</li>
<li>比较接口值</li>
<li>类型断言：x.(T)</li>
<li>类型分支：x.(type)</li>
</ul>
<p><em>这里的T是一个类型。</em>  </p>
<h4 id="zhi-lei-xing-jie-shou-zhe-he-zhi-zhen-lei-xing-jie-shou-zhe"><a class="toclink" href="#zhi-lei-xing-jie-shou-zhe-he-zhi-zhen-lei-xing-jie-shou-zhe">值类型接收者和指针类型接收者</a></h4>
<p>调用方法的时候，值类型和指针类型都可以调用方法。  </p>
<p>调用方法时，既可以用指针也可以用值。<br>
Go语言编译器会自动帮我们取对应的类型以满足方法接收者的要求：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">user</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// 值类型的方法</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">user</span><span class="p">)</span><span class="w"> </span><span class="nx">hello</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;Hello,&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">u</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// 指针类型的方法</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="o">*</span><span class="nx">user</span><span class="p">)</span><span class="w"> </span><span class="nx">rename</span><span class="p">(</span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u</span><span class="p">.</span><span class="nx">name</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">name</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">user</span><span class="p">{</span><span class="s">&quot;Tom&quot;</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="p">.</span><span class="nx">rename</span><span class="p">(</span><span class="s">&quot;Tim&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">u2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">user</span><span class="p">{</span><span class="s">&quot;Jack&quot;</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">u2</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">u2</span><span class="p">.</span><span class="nx">rename</span><span class="p">(</span><span class="s">&quot;Jhon&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">u2</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>在定义方法的时候，既可以将方法绑定到值类型，也可以将方法绑定到指针类型。  </p>
<p><strong>方法集合</strong><br>
值类型的方法集合，只有用值类型定义的方法。<br>
指针类型的方法集合，包括值类型定义的方法和指针类型定义的方法。  </p>
<p>要实现一个接口，必须实现接口的所有方法。<br>
以值类型接收者实实现接口的时候，指针类型和值类型都实现了接口。<br>
以指针类型接收者实现的接口的时候，只有指针类型才被认为实现了接口。  </p>
<p>定义接口如下：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">userObj</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">rename</span><span class="p">(</span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">hello</span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">userObj</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">rename</span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">userObj</span><span class="p">,</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u</span><span class="p">.</span><span class="nx">rename</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">user</span><span class="p">{</span><span class="s">&quot;Tom&quot;</span><span class="p">}</span><span class="w">  </span><span class="c1">// 这个是值</span><span class="w"></span>
<span class="w">    </span><span class="nx">hello</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">u1</span><span class="p">)</span><span class="w">         </span><span class="c1">// 传指针给函数</span><span class="w"></span>
<span class="w">    </span><span class="nx">rename</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">u1</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Jack&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">hello</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">u1</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这个接口要满足2个方法，值类型的接收者的方法集只有一个方法，不满足接口。只有指针类型的才满足接口。所以必须传指针，如果直接把值传给函数，就会报错：</p>
<div class="highlight"><pre><span></span><code># command-line-arguments
.\main.go:32:7: cannot use u1 (type user) as type userObj in argument to hello:
        user does not implement userObj (rename method has pointer receiver)
</code></pre></div>

<p>上面的例子里定义的是值类型的变的，调用函数的时候，需要传指针给函数。也可以直接定义指针类型变量，然后直接用：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">u1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">user</span><span class="p">{</span><span class="s">&quot;Tom&quot;</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">hello</span><span class="p">(</span><span class="nx">u1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">rename</span><span class="p">(</span><span class="nx">u1</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Jack&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">hello</span><span class="p">(</span><span class="nx">u1</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="xiao-jie"><a class="toclink" href="#xiao-jie">小结</a></h4>
<p>对于方法：</p>
<ul>
<li>调用方法时，无论是用值还是用指针都可以，编译器会自动做转换</li>
<li>定义方法时，可以用值，也可以用指针。但是如果用了指针，那么建议所有的方法都用指针（建议，非强制）</li>
<li>如果全部的方法都是值类型实现的，那么在判断是否满足接口的时候，值类型和指针类型都会满足接口。否则可能只有指针类型才满足接口</li>
<li>函数和方法的调用，传参的时候都是副本，调用会有一次拷贝。对于特别大的对象，考虑用指针，这样只需要拷贝一个地址</li>
<li>要修改值类型的对象，就需要传指针给方法，否则原值不会变</li>
</ul>
<p>对于接口：</p>
<ul>
<li>如果类型对于接口的实现都是值类型的方法，那么该类型的值和指针都实现了接口</li>
<li>如果类型对于接口的实现有指针类型的方法，那么只有指针实现了接口，需要传指针给调用的函数</li>
</ul>
<p>使用的时候：</p>
<ul>
<li>调用方法时，用值或者用指针都可以，不纠结直接写变量名就好</li>
<li>传参给函数（或方法）的接口类型，或者是给接口赋值时，似乎传指针是不会错的</li>
<li>接上一条，如果实现接口的方法都是值类型接收者的话，那么也就不用纠结了</li>
</ul>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>